from msg import *
import globals
import yaml
import time
import threading
import SocketServer
from SocketServer import TCPServer, ThreadingMixIn, StreamRequestHandler
import socket
import time
import sys
import ReceiveMessage
from configuration import *
from QueryUsers import query_users
#from ReceiveMessage import receive_message
import configfile
import GetDataFromAuthServer
import types

mp=None;
recethreadstate=True
sendalivethreadstate= True
showAliveMessage=False


class messagePasser:
    thisID=0;
    thisName= '';
    thisIp = '';
    thisPort =1;
    thisGroup= None;
    thisConfigRout='';
    #thisConfiguration = None;
    ConfigurationMap = {};
    thisConfigFile = None;
    connectionPool=None;
    recethread=None;
    messageRecord=set();
    hintMap={};
    hintId=0;
    conflictCounter=0;
    conflictCounterLock=threading.RLock()

    global recethreadstate;

    def __init__(self, thisName, lors):

        self.thisName = thisName;
        #self.thisConfigRout = configRout;
        #self.thisConfigFile = yaml_configuration(configRout);
        #self.thisConfiguration= self.thisConfigFile.getConfiguration();
        #find = False;
        #data = GetDataFromAuthServer.get_graph_from_auth_server()
        #self.ConfigurationMap = yaml.load(data)

        data = GetDataFromAuthServer.get_config_from_auth_server(thisName)
        if data == "error" :
            sys.exit()
        self.thisConfiguration = yaml.load(data)

        #print "In message passer config : ",
        #print self.thisConfiguration

        globals.globalConfiguration = self.thisConfiguration

        for data in self.thisConfiguration:
            configfile.comGraph[data['name']] = data['group']
            self.ConfigurationMap[data['name']]= data;
            if data['name']==thisName:
                find = True;
                self.thisIp = data['ip'];
                self.thisPort = data['port'];
                self.thisGroup = data['group'];

        if find==False:
            print "Wrong MP's name.";
            sys.exit(0);

        if lors =='l':
            configRout=''
            self.recethread= receivethread(self.thisPort, self.thisIp, self, self.thisConfiguration, configRout)
            self.recethread.start()
            self.alivethread = sendalivethread(self.thisPort, self.thisIp, self, self.thisConfiguration, configRout)
            self.alivethread.start()
        print "MessagePasser is initiated.";

    def __repr__(self):
        return "MessagePasser Name=%s IP=%s Port=%d Group=%s" %(
                self.thisName, self.thisIp, self.thisPort, self.thisGroup);

    def send(self, msg):
        #print "Sending message from ->%s to -> %s type %s" % (msg.src, msg.dest, msg.mtype)
        #print "In send message is : ",
        #print msg;
        #print "In send the destArray is : ",
        #print msg.destArray

        dest = msg.getDest();
        msg.setID(self.thisID);
        self.thisID=self.thisID+1;
        errorDest=[]
        if type(dest)==type('x'):
            if (not self.sendMessage(msg)):
                errorDest.append(d)
        else:
            for d in dest:
                if not d==mp.thisName:
                    temp = msg.clone();
                    temp.setID(msg.getID());
                    temp.setDest(d);
                    #print "Multicast: "
                    #print temp
                    if (not self.sendMessage(temp)):
                        errorDest.append(d);
        return errorDest

    def sendMessage(self, msg):
        destName = msg.getDest();
        try:
            #print "---------------------\n SENDING"
            #print msg
            #print "---------------------"
    #        print "Im in sendmessage"
        #    print msg.src
        #    print msg.dest
        #    print msg.data
        #    print msg.destArray
        #    print "---------------------"
            configData = self.ConfigurationMap[destName];
            s=socket.socket(socket.AF_INET, socket.SOCK_STREAM);
            #print "send to "+configData['ip']+ " port : " + str(configData['port']);
            s.connect((configData['ip'], configData['port']));
            s.send(yaml.dump(msg));
            #print "is sent";
            return True;
        except KeyError:
            print "Error: The destnation of Message %s can't be figured." %(msg.getDest());
        except Exception,e:
            #print e;
            return False;
class Hint:
    userListHashCode=0
    hintId=0
    def __init__(self, userListHashCode, hintId):
        self.userListHashCode = userListHashCode
        self.hintId = hintId

class sendalivethread(threading.Thread):
    thisPort=0;
    parent = None;
    thisConfiguration = None;
    thisConfigRout = '';
    thread_stop = False;
    thisIp='';
    server=None;
    global sendalivethreadstate

    def __init__(self, port, ip, mp, configuration, configfilename):
        self.thisPort= port;
        self.parent = mp;
        self.thisConfiguration = configuration;
        self.thisConfigRout = configfilename;
        self.thisIp= ip;
        threading.Thread.__init__(self);

    def run(self):
        #print "### in alive thread"
        global sendalivethreadstate
        while (sendalivethreadstate):
            time.sleep(5)
            mp.hintId=mp.hintId+1
            hint = Hint(hash(query_users()),mp.hintId)

            configfile.get_node_neighbors(mp.thisName)

            for d in self.parent.thisGroup:
                tmp = []
                tmp.append(d)
                alivemsg = Message(mp.thisName, tmp, 'time',yaml.dump(hint),'alive', None)
                self.parent.send(alivemsg)

class receivethread(threading.Thread):
    thisPort=0;
    parent = None;
    thisConfiguration = None;
    thisConfigRout = '';
    thread_stop = False;
    thisIp='';
    server=None;
    global recethreadstate;
    global sendalivethreadstate


    def __init__(self, port, ip, mp, configuration, configfilename):
        self.thisPort= port;
        self.parent = mp;
        self.thisConfiguration = configuration;
        self.thisConfigRout = configfilename;
        self.thisIp= ip;
        threading.Thread.__init__(self);

    def run(self):
        global recethreadstate
        global sendalivethreadstate
        host, port = self.thisIp, self.thisPort;
        #  self.server = SocketServer.TCPServer((host, port), MyTCPHandler);
        try:
            #print host + ' ' + port
            self.server = Server((host, port), MyTCPHandler);
            self.server.serve_forever();
        except:
            sendalivethreadstate= False
            print "Wrong listening port or IP. Ctrl+C"


class Server(ThreadingMixIn,TCPServer): pass

class MyTCPHandler(SocketServer.BaseRequestHandler):

    #global globalActiveUserList
    #global globalActiveUserListLock
    #global showAliveMessage
    def handle(self):
        self.data = self.request.recv(4096).strip();
        recemsg = yaml.load(self.data);
        #print "@@@@@@@@@@@@@\n RECEIVE"
        #print recemsg
        #print "@@@@@@@@@@@@@"
        #print "Debug: **",
        #print recemsg

        #print "Debug ** source %s and mid %s" % (recemsg.src, recemsg.mid)
        #print recemsg.src
        #print recemsg.mid
        # mp.messageRecord.add((recemsg.src, recemsg.mid));

        #if recemsg.dest=='a':
        #    time.sleep(6);
        #print recemsg;
        if recemsg.mtype!='ack':
            temp = []
            temp.append(recemsg.src)
            ackmsg = Message(mp.thisName, temp, 'time', yaml.dump(recemsg),'ack', None)
          #  mp.send(ackmsg)
            self.messagehandler(recemsg)

            '''
            if len(recemsg.destArray)>1:
                dest = recemsg.destArray;
                for d in dest:
                    if d!=mp.thisName:
                        msg=recemsg.clone();
                        msg.setDest(d);

                        #print "In send Making ack source is  ** : ",
                        #print recemsg.dest
                        ackmsg= Message(mp.thisName, d, 'time', yaml.dump(msg),'ack', None);
                        #print "@@@@@@"
                        #print "Setting destination to "
                        #print d
                        #print ackmsg.src
                        #print "@@@@@@"
                        mp.send(ackmsg);
                        self.messagehandler(recemsg);
                        '''
        if recemsg.mtype=='ack':
            newmsg = yaml.load(recemsg.data)
            testtuple = (newmsg.src, newmsg.mid);
            if mp.messageRecord.__contains__(testtuple):
                a = 1
                #print "Receive duplication";
            else:
                b = 1
                #print "Debug else part"
                '''
               if len(newmsg.destArray)>1:
                    dest = newmsg.destArray;
                    for d in dest:
                        if d!=newmsg.dest:
                            msg=newmsg.clone();
                            msg.setDest(d);
                            ackmsg= Message(newmsg.dest, d, 'time', yaml.dump(msg),'ack');
                            mp.send(ackmsg);
                            self.messagehandler(newmsg);
        '''
    def messagehandler(self, message):
        #print "in messagehandler"
        #print message;
        #print message
        #print message.destArray
        global showAliveMessage
        #global globalActiveUserListLock
        #global globalActiveUserList

        if message.mtype == 'alive':
            hint = yaml.load(message.data)
            localHashCode=hash(query_users())
            if showAliveMessage == True:
                print "alive from",
                print message.src,

                print " with ",
                print hint.userListHashCode,
                print "local ULHC=",
                print localHashCode,

            mp.conflictCounterLock.acquire()
            if localHashCode!=hint.userListHashCode:
                mp.hintMap[message.src]=(hint.hintId, "not match")
                if showAliveMessage == True:
                    print "not match"
            else:
                mp.hintMap[message.src]=hint.hintId, "match"
                if showAliveMessage == True:
                    print "match"
            if hint.hintId>mp.hintId:
                mp.hintId= hint.hintId
            countSum =0;
            countNotMatch=0;
            for d in mp.hintMap:
                if mp.hintMap[d][1]=="not match":
             #    if mp.hintMap[d][0]==mp.hintId:
                    countNotMatch=countNotMatch+1
                countSum=countSum+1


            if countNotMatch>countSum/2:
                mp.conflictCounter=mp.conflictCounter+1
            else:
                if mp.conflictCounter>0:
                    mp.conflictCounter=mp.conflictCounter-1
            if showAliveMessage == True:
                print "conflict counter: ",
                print mp.conflictCounter
            if mp.conflictCounter>5:
                mp.conflictCounter=0
                print "send reqeuest"

                for d in mp.hintMap:
                    if mp.hintMap[d][1]=="not match":
                        temp=[]
                        temp.append(d)
                        requestmsg = Message(mp.thisName, temp, 'time','','requestUL', None)
                        mp.send(requestmsg)
                        break
            mp.conflictCounterLock.release()

        else:
            if message.mtype == 'requestUL':
                globals.globalActiveUserListLock.acquire()
                temp=[]
                temp.append(message.src)
                answermsg = Message(mp.thisName, temp, 'time',yaml.dump(globals.globalActiveUserList),'answerUL', None)
                globals.globalActiveUserListLock.release()
                mp.send(answermsg)
            else:
                if message.mtype=='answerUL':
                    globals.globalActiveUserListLock.acquire()
                    temp=yaml.load(message.data)
                    globals.globalActiveUserList = {}
                    # print "globalActiveUserList1 : ",
                    print globals.globalActiveUserList
                    for d in temp:
                        globals.globalActiveUserList[d]=temp[d]
                    globals.globalActiveUserListLock.release()
                    print "UpdateLocalUserList : ",
                    print globals.globalActiveUserList
                else:
                    ReceiveMessage.receive_message (mp, message);


if __name__ == "__main__":
    name = raw_input('Enter mp name: ');
    mp1=messagePasser('D:\Python27\demo.yaml',name);
    newmsg= Message('a','b','time','data','type');
    if name=='a':
        mp1.send(newmsg);
